﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.ServiceModel;

namespace RemoteWorker.Server
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, IncludeExceptionDetailInFaults = true)]
    public class WorkerServer : IWorkerServer
    {
        public WorkerServer()
        {
            _workerPingTimeOut = TimeSpan.FromMilliseconds(Convert.ToInt32(ConfigurationManager.AppSettings["WorkerPingTimeOut"]));
        }

        public void Ping(string name)
        {
            if (_workers.ContainsKey(name))
            {
                Worker worker = _workers[name];
                worker.LastPing = DateTime.Now;
                worker.CallbackWorker = OperationContext.Current.GetCallbackChannel<IWorker>();
                Console.WriteLine("Ping from worker {0}", name);
            }
            else
            {
                Console.WriteLine("Worker registred {0}", name);
                _workers[name] = new Worker(name, OperationContext.Current.GetCallbackChannel<IWorker>());
            }
        }

        public void SendOutput(string data)
        {
            Console.WriteLine(">>> {0}", data);
            if (_currentTask != null)
                _currentTask.Log(data);
        }

        public void Disconnect(string name)
        {
            Console.WriteLine("{0} - Client called 'Disconnect'", DateTime.Now);
        }

        public bool CheckWorker(string workerName)
        {
            _CleanWorkersByTimeOut();

            return _workers.ContainsKey(workerName.ToUpper());
        }

        public void Execute(INantTask task, string workerName, string fileName, string args)
        {
            _currentTask = task;

            Console.WriteLine("Execute '{0}' '{1}'", fileName, args);

            Worker worker = GetWorker(workerName);
            worker.CallbackWorker.Execute(fileName, args);
        }

        public void Complite(int exitCode)
        {
            Console.WriteLine("Complite");
            if (_currentTask != null)
            {
                Console.WriteLine(">>> Complite");
                _currentTask.Complete(exitCode);
            }
        }

        public Worker GetWorker(string workerName)
        {
            return _workers[workerName.ToUpper()];
        }

        private void _CleanWorkersByTimeOut()
        {
            IList<string> workerNames = new List<string>(_workers.Keys);

            foreach (var workerName in workerNames)
            {
                if (DateTime.Now - _workers[workerName].LastPing > _workerPingTimeOut)
                    _workers.Remove(workerName);
            }
        }

        private IDictionary<string, Worker> _workers = new Dictionary<string, Worker>();
        private INantTask _currentTask;
        private TimeSpan _workerPingTimeOut;
    }
}